From 2793304117c19665f089c7bc25cfe060bbbec1ac Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 19 Nov 2022 23:16:07 +0100 Subject: Vulkan: Allow stagging buffer deferrals. --- .../renderer_vulkan/vk_staging_buffer_pool.cpp | 51 +++++++++++++++------- .../renderer_vulkan/vk_staging_buffer_pool.h | 26 ++++++++--- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 06f68d09a..202806331 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later #include #include @@ -94,7 +94,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem .flags = 0, .size = STREAM_BUFFER_SIZE, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT , .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, @@ -142,11 +142,23 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem StagingBufferPool::~StagingBufferPool() = default; -StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) { - if (usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) { +StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage, bool deferred) { + if (!deferred && usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) { return GetStreamBuffer(size); } - return GetStagingBuffer(size, usage); + return GetStagingBuffer(size, usage, deferred); +} + +void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) { + auto& entries = GetCache(ref.usage)[ref.log2_level].entries; + const auto is_this_one = [&ref](const StagingBuffer& entry) { + return entry.index == ref.index; + }; + auto it = std::find_if(entries.begin(), entries.end(), is_this_one); + ASSERT(it != entries.end()); + ASSERT(it->deferred); + it->tick = scheduler.CurrentTick(); + it->deferred = false; } void StagingBufferPool::TickFrame() { @@ -196,19 +208,21 @@ bool StagingBufferPool::AreRegionsActive(size_t region_begin, size_t region_end) [gpu_tick](u64 sync_tick) { return gpu_tick < sync_tick; }); }; -StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage) { - if (const std::optional ref = TryGetReservedBuffer(size, usage)) { +StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage, + bool deferred) { + if (const std::optional ref = TryGetReservedBuffer(size, usage, deferred)) { return *ref; } - return CreateStagingBuffer(size, usage); + return CreateStagingBuffer(size, usage, deferred); } std::optional StagingBufferPool::TryGetReservedBuffer(size_t size, - MemoryUsage usage) { + MemoryUsage usage, + bool deferred) { StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)]; const auto is_free = [this](const StagingBuffer& entry) { - return scheduler.IsFree(entry.tick); + return !entry.deferred && scheduler.IsFree(entry.tick); }; auto& entries = cache_level.entries; const auto hint_it = entries.begin() + cache_level.iterate_index; @@ -220,11 +234,14 @@ std::optional StagingBufferPool::TryGetReservedBuffer(size_t s } } cache_level.iterate_index = std::distance(entries.begin(), it) + 1; - it->tick = scheduler.CurrentTick(); + it->tick = deferred ? std::numeric_limits::max() : scheduler.CurrentTick(); + ASSERT(!it->deferred); + it->deferred = deferred; return it->Ref(); } -StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage) { +StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, + bool deferred) { const u32 log2 = Common::Log2Ceil64(size); vk::Buffer buffer = device.GetLogical().CreateBuffer({ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, @@ -233,7 +250,7 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage .size = 1ULL << log2, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT , .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, @@ -249,7 +266,11 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage .buffer = std::move(buffer), .commit = std::move(commit), .mapped_span = mapped_span, - .tick = scheduler.CurrentTick(), + .usage = usage, + .log2_level = log2, + .index = unique_ids++, + .tick = deferred ? std::numeric_limits::max() : scheduler.CurrentTick(), + .deferred = deferred, }); return entry.Ref(); } diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 91dc84da8..2906d92a4 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -1,5 +1,6 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #pragma once @@ -20,6 +21,9 @@ struct StagingBufferRef { VkBuffer buffer; VkDeviceSize offset; std::span mapped_span; + MemoryUsage usage; + u32 log2_level; + u64 index; }; class StagingBufferPool { @@ -30,7 +34,8 @@ public: Scheduler& scheduler); ~StagingBufferPool(); - StagingBufferRef Request(size_t size, MemoryUsage usage); + StagingBufferRef Request(size_t size, MemoryUsage usage, bool deferred = false); + void FreeDeferred(StagingBufferRef& ref); void TickFrame(); @@ -44,13 +49,20 @@ private: vk::Buffer buffer; MemoryCommit commit; std::span mapped_span; + MemoryUsage usage; + u32 log2_level; + u64 index; u64 tick = 0; + bool deferred{}; StagingBufferRef Ref() const noexcept { return { .buffer = *buffer, .offset = 0, .mapped_span = mapped_span, + .usage = usage, + .log2_level = log2_level, + .index = index, }; } }; @@ -68,11 +80,12 @@ private: bool AreRegionsActive(size_t region_begin, size_t region_end) const; - StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage); + StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage, bool deferred = false); - std::optional TryGetReservedBuffer(size_t size, MemoryUsage usage); + std::optional TryGetReservedBuffer(size_t size, MemoryUsage usage, + bool deferred); - StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage); + StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage, bool deferred); StagingBuffersCache& GetCache(MemoryUsage usage); @@ -99,6 +112,7 @@ private: size_t current_delete_level = 0; u64 buffer_index = 0; + u64 unique_ids{}; }; } // namespace Vulkan -- cgit v1.2.3